#include "libArchivoConfiguracion.h"

//TODO modificar los parametros de leerArchivoConfiguracion
uint8_t leerArchivoConfiguracion(archConfig_t* archConfig, uint8_t imprimirDebug) {
	archConfigAux_t archConfigAux;

	archConfigAux.tamanio.id = (char*) malloc(8);
	memset(archConfigAux.tamanio.id, '\0', 8);
	strcpy(archConfigAux.tamanio.id, "Tamanio");
	archConfigAux.tamanio.valor = -1;

	archConfigAux.tamanioChunk.id = (char*) malloc(13);
	memset(archConfigAux.tamanioChunk.id, '\0', 13);
	strcpy(archConfigAux.tamanioChunk.id, "TamanioChunk");
	archConfigAux.tamanioChunk.valor = -1;

	archConfigAux.adminMemoria.id = (char*) malloc(24);
	memset(archConfigAux.adminMemoria.id, '\0', 24);
	strcpy(archConfigAux.adminMemoria.id, "AdministraciondeMemoria");
	archConfigAux.adminMemoria.valor = NULL;

	archConfigAux.algoritmoEleccion.id = (char*) malloc(20);
	memset(archConfigAux.algoritmoEleccion.id, '\0', 20);
	strcpy(archConfigAux.algoritmoEleccion.id, "AlgoritmodeEleccion");
	archConfigAux.algoritmoEleccion.valor = NULL;

	archConfigAux.algoritmoReemplazo.id = (char*) malloc(21);
	memset(archConfigAux.algoritmoReemplazo.id, '\0', 21);
	strcpy(archConfigAux.algoritmoReemplazo.id, "AlgoritmodeReemplazo");
	archConfigAux.algoritmoReemplazo.valor = NULL;

	archConfigAux.frecuenciaCompactacion.id = (char*) malloc(25);
	memset(archConfigAux.frecuenciaCompactacion.id, '\0', 25);
	strcpy(archConfigAux.frecuenciaCompactacion.id, "FrecuenciadeCompactacion");
	archConfigAux.frecuenciaCompactacion.valor = -1;

	archConfigAux.cantidadConexiones.id = (char*) malloc(21);
	memset(archConfigAux.cantidadConexiones.id, '\0', 21);
	strcpy(archConfigAux.cantidadConexiones.id, "CantidaddeConexiones");
	archConfigAux.cantidadConexiones.valor = -1;

	archConfigAux.nivelLog.id = (char*) malloc(14);
	memset(archConfigAux.nivelLog.id, '\0', 14);
	strcpy(archConfigAux.nivelLog.id, "NiveldeLogueo");
	archConfigAux.nivelLog.valor = -1;

	if (imprimirDebug) {
		printf("Se intentara abrir el archivo de configuracion.\n");
	}
	FILE* fp;
	fp = fopen(PATH_ARCHIVO_CONFIGURACION, "r");
	if (fp != NULL) {
		//EL ARCHIVO DE CONFIGURACION FUE ABIERTO EXITOSAMENTE
		if (imprimirDebug) {
			printf("El archivo de configuracion fue abierto exitosamente.\n");
		}
		fseek(fp, 0, SEEK_SET);
		uint8_t finLectura = 0;
		while (!finLectura) {
			if (imprimirDebug) {
				printf("Se intentara leer una linea del archivo de configuracion.\n");
			}
			finLectura = leerLinea(fp, &archConfigAux, imprimirDebug);
		}
		if (finLectura == 1) {
			//EL FORMATO DEL ARCHIVO ES CORRECTO
			if (imprimirDebug) {
				printf("Se termino de leer el archivo.\n");
			}
			uint8_t archivoIncompleto = archivoDeConfiguracionNoCompleto(archConfigAux);
			fclose(fp);
			if (!archivoIncompleto) {
				if (imprimirDebug) {
					printf("El archivo contenia todos los datos esperados.\n");
				}
				(*archConfig).tamanio = (uint32_t) archConfigAux.tamanio.valor;
				(*archConfig).tamanioChunk = (uint16_t) archConfigAux.tamanioChunk.valor;
				(*archConfig).adminMemoria = (char*) malloc(strlen(archConfigAux.adminMemoria.valor) + 1);
				memset((*archConfig).adminMemoria, '\0', strlen(archConfigAux.adminMemoria.valor) + 1);
				strcpy((*archConfig).adminMemoria, archConfigAux.adminMemoria.valor);
				(*archConfig).algoritmoEleccion = (char*) malloc(strlen(archConfigAux.algoritmoEleccion.valor) + 1);
				memset((*archConfig).algoritmoEleccion, '\0', strlen(archConfigAux.algoritmoEleccion.valor) + 1);
				strcpy((*archConfig).algoritmoEleccion, archConfigAux.algoritmoEleccion.valor);
				(*archConfig).algoritmoReemplazo = (char*) malloc(strlen(archConfigAux.algoritmoReemplazo.valor) + 1);
				memset((*archConfig).algoritmoReemplazo, '\0', strlen(archConfigAux.algoritmoReemplazo.valor) + 1);
				strcpy((*archConfig).algoritmoReemplazo, archConfigAux.algoritmoReemplazo.valor);
				(*archConfig).frecuenciaCompactacion = (uint8_t) archConfigAux.frecuenciaCompactacion.valor;
				(*archConfig).cantidadConexiones = (uint8_t) archConfigAux.cantidadConexiones.valor;
				(*archConfig).nivelLog = (uint8_t) archConfigAux.nivelLog.valor;
				return 0;
			} else {
				printf("------------------------------------------------------------\n");
				printf("--                         ERROR                          --\n");
				printf("------------------------------------------------------------\n");
				printf("El archivo no contenia todos los datos esperados.\n");
				printf("------------------------------------------------------------\n");
				printf("\n");
				return 1;
			}
		} else if (finLectura == 2) {
			//EL FORMATO DEL ARCHIVO ES INCORRECTO
			printf("------------------------------------------------------------\n");
			printf("--                         ERROR                          --\n");
			printf("------------------------------------------------------------\n");
			printf("El formato del archivo de configuracion es incorrecto.\n");
			printf("El formato debe ser el siguiente:\n");
			printf("Tamanio: <Valor>\n");
			printf("Tamanio Chunk: <Valor>\n");
			printf("Administracion de Memoria: <Valor>\n");
			printf("Algoritmo de Eleccion: <Valor>\n");
			printf("Algoritmo de Reemplazo: <Valor>\n");
			printf("Frecuencia de Compactacion: <Valor>\n");
			printf("Cantidad de Conexiones: <Valor>\n");
			printf("Nivel de Logueo: <Valor>@\n");
			printf("Notas:\n");
			printf("Los espacios seran ignorados tanto en las Id como el el valor de los datos.\n");
			printf("El caracter @ debe marcar el fin del archivo.\n");
			printf("------------------------------------------------------------\n");
			printf("\n");
			fclose(fp);
			return 2;
		} else {
			return 4;
		}
	} else {
		//EL ARCHIVO DE CONFIGURACION NO PUDO SER ABIERTO
		printf("------------------------------------------------------------\n");
		printf("--                         ERROR                          --\n");
		printf("------------------------------------------------------------\n");
		printf("El archivo de configuracion no pudo ser abierto.\n");
		printf("Compruebe que se encuentre en [%s].\n", PATH_ARCHIVO_CONFIGURACION);
		printf("------------------------------------------------------------\n");
		printf("\n");
		return 3;
	}
}

uint8_t leerLinea(FILE* fp, archConfigAux_t* archConfigAux, uint8_t imprimirDebug) {
	char *buffer = (char*) malloc(MAX_LINEA_ARCHIVO_CONFIGURACION + 1);
	memset(buffer, '\0', MAX_LINEA_ARCHIVO_CONFIGURACION + 1);
	char caracter;
	fread(&caracter, 1, 1, fp);
	uint8_t pos;
	for (pos = 0; pos < MAX_LINEA_ARCHIVO_CONFIGURACION && caracter != '\n' && caracter != '@'; pos++) {
		buffer[pos] = caracter;
		fread(&caracter, 1, 1, fp);
	}
	if (imprimirDebug) {
		printf("Se leyo la linea [%s].\n", buffer);
	}
	uint8_t errorDeFormato;
	errorDeFormato = parsearLinea(buffer, archConfigAux, imprimirDebug);
	if (errorDeFormato) {
		free(buffer);
		return 2;
	} else if (caracter == '@') {
		free(buffer);
		return 1;
	} else {
		free(buffer);
		return 0;
	}
}

uint8_t parsearLinea(char* buffer, archConfigAux_t* archConfigAux, uint8_t imprimirDebug) {
	char *id;
	char *valor;
	eliminarEspaciosDeCadena(&buffer);
	uint8_t errorDeFormato = 0;
	errorDeFormato = separarIdDeValor(buffer, &id, &valor);
	if (!errorDeFormato) {
		if (strcmp(id, (*archConfigAux).tamanio.id) == 0) {
			(*archConfigAux).tamanio.valor = atoi(valor);
			if (imprimirDebug) {
				printf("Se ha asignado a la variable con id [%s] el valor [%d].\n", (*archConfigAux).tamanio.id, (int32_t) (*archConfigAux).tamanio.valor);
			}
			return 0;
		} else if (strcmp(id, (*archConfigAux).tamanioChunk.id) == 0) {
			(*archConfigAux).tamanioChunk.valor = atoi(valor);
			if (imprimirDebug) {
				printf("Se ha asignado a la variable con id [%s] el valor [%d].\n", (*archConfigAux).tamanioChunk.id, (*archConfigAux).tamanioChunk.valor);
			}
			return 0;
		} else if (strcmp(id, (*archConfigAux).adminMemoria.id) == 0) {

			uint8_t i;
			for (i = 0; valor[i] != '\0'; i++)
				;
			(*archConfigAux).adminMemoria.valor = (char*) malloc(i + 1);
			memset((*archConfigAux).adminMemoria.valor, '\0', i + 1);
			for (i = 0; valor[i] != '\0'; i++) {
				(*archConfigAux).adminMemoria.valor[i] = valor[i];
			}
			if (imprimirDebug) {
				printf("Se ha asignado a la variable con id [%s] el valor [%s].\n", (*archConfigAux).adminMemoria.id, (*archConfigAux).adminMemoria.valor);
			}
			return 0;
		} else if (strcmp(id, (*archConfigAux).algoritmoEleccion.id) == 0) {
			uint8_t i;
			for (i = 0; valor[i] != '\0'; i++)
				;
			(*archConfigAux).algoritmoEleccion.valor = (char*) malloc(i + 1);
			memset((*archConfigAux).algoritmoEleccion.valor, '\0', i + 1);
			for (i = 0; valor[i] != '\0'; i++) {
				(*archConfigAux).algoritmoEleccion.valor[i] = valor[i];
			}
			if (imprimirDebug) {
				printf("Se ha asignado a la variable con id [%s] el valor [%s].\n", (*archConfigAux).algoritmoEleccion.id, (*archConfigAux).algoritmoEleccion.valor);
			}
			return 0;
		} else if (strcmp(id, (*archConfigAux).algoritmoReemplazo.id) == 0) {
			uint8_t i;
			for (i = 0; valor[i] != '\0'; i++)
				;
			(*archConfigAux).algoritmoReemplazo.valor = (char*) malloc(i + 1);
			memset((*archConfigAux).algoritmoReemplazo.valor, '\0', i + 1);
			for (i = 0; valor[i] != '\0'; i++) {
				(*archConfigAux).algoritmoReemplazo.valor[i] = valor[i];
			}
			if (imprimirDebug) {
				printf("Se ha asignado a la variable con id [%s] el valor [%s].\n", (*archConfigAux).algoritmoReemplazo.id, (*archConfigAux).algoritmoReemplazo.valor);
			}
			return 0;
		} else if (strcmp(id, (*archConfigAux).frecuenciaCompactacion.id) == 0) {
			(*archConfigAux).frecuenciaCompactacion.valor = atoi(valor);
			if (imprimirDebug) {
				printf("Se ha asignado a la variable con id [%s] el valor [%d].\n", (*archConfigAux).frecuenciaCompactacion.id, (*archConfigAux).frecuenciaCompactacion.valor);
			}
			return 0;
		} else if (strcmp(id, (*archConfigAux).cantidadConexiones.id) == 0) {
			(*archConfigAux).cantidadConexiones.valor = atoi(valor);
			if (imprimirDebug) {
				printf("Se ha asignado a la variable con id [%s] el valor [%d].\n", (*archConfigAux).cantidadConexiones.id, (*archConfigAux).cantidadConexiones.valor);
			}
		} else if (strcmp(id, (*archConfigAux).nivelLog.id) == 0) {
			(*archConfigAux).nivelLog.valor = atoi(valor);
			if (imprimirDebug) {
				printf("Se ha asignado a la variable con id [%s] el valor [%d].\n", (*archConfigAux).nivelLog.id, (*archConfigAux).nivelLog.valor);
			}
			return 0;
		} else {
			return 1;
		}
	} else {
		return 2;
	}
	return 0;
}

void eliminarEspaciosDeCadena(char** buffer) {
	uint8_t i;
	uint8_t j;
	for (i = 0, j = 0; j < MAX_LINEA_ARCHIVO_CONFIGURACION; j++) {
		if ((*buffer)[j] != ' ') {
			(*buffer)[i] = (*buffer)[j];
			i++;
		}
	}
}

uint8_t separarIdDeValor(char* buffer, char** id, char** valor) {
	uint8_t i;
	for (i = 0; i < MAX_LINEA_ARCHIVO_CONFIGURACION && buffer[i] != ':' && buffer[i] != '\0'; i++)
		;
	if (buffer[i] == ':') {
		*id = (char*) malloc(i + 1);
		memset(*id, '\0', i + 1);
		for (i = 0; buffer[i] != ':'; i++) {
			(*id)[i] = buffer[i];
		}
		i++;
		uint8_t j;
		for (j = i; j < MAX_LINEA_ARCHIVO_CONFIGURACION && buffer[j] != '\0'; j++)
			;
		*valor = (char*) malloc(j - i + 1);
		memset(*valor, '\0', j - i + 1);
		for (j = 0; buffer[i] != '\0'; i++, j++) {
			(*valor)[j] = buffer[i];
		}
		return 0;
	} else {
		return 2;
	}
}

uint8_t archivoDeConfiguracionNoCompleto(archConfigAux_t archConfigAux) {
	if (archConfigAux.tamanio.valor != -1 && archConfigAux.tamanioChunk.valor != -1 && archConfigAux.adminMemoria.valor != NULL && (strcmp(archConfigAux.algoritmoEleccion.valor, "WorstFit") == 0 || strcmp(archConfigAux.algoritmoEleccion.valor, "NextFit") == 0) && (strcmp(archConfigAux.algoritmoReemplazo.valor, "LRU") == 0 || strcmp(archConfigAux.algoritmoReemplazo.valor, "FIFO") == 0) && archConfigAux.frecuenciaCompactacion.valor != -1 && archConfigAux.cantidadConexiones.valor != -1 && archConfigAux.nivelLog.valor != -1) {
		return 0;
	} else {
		return 2;
	}
}

